#!/usr/bin/env python
# coding=utf-8
import pretty_errors
from lxml import etree

'''
 参考网址 
 https://www.jianshu.com/p/72eee4a0ac47
 https://www.cnblogs.com/lei0213/p/7506130.html
 https://cuiqingcai.com/5545.html 书本官网
 https://www.w3school.com.cn/xpath/xpath_functions.asp  w3c参考
 https://lxml.de/ lxml官方文档
'''
# 4.1 使用XPath
'''
XPath常用规则
nodename    --选取此节点的所有子节点
/           --从当前节点选取直接子节点
//          --从当前节点选取子孙节点
.           --选取当前节点
..          --选取当前结点的父节点
@           --选取属性
'''
# 4.实例引入
text = '''
<div>
<ul>
<li class="itrm-0"><a href="link1.html">first item</a></li>
<li class="itrm-1"><a href="link2.html">second item</a></li>
<li class="itrm-inactive"><a href="link3.html">third item</a></li>
<li class="itrm-1"><a href="link4.html">fourth item</a></li>
<li class="itrm-0"><a href="link5.html">fifth item</a>
</ul>
</div>
'''
html = etree.HTML(text)  # etree用于修正html文本
result = etree.tostring(html)  # 输出修正后的html文本,输出为bytes类型
print('\n 解析html文本段')
print(result.decode('utf-8'))  # decode转换为str类型

# 读取文本解析
html = etree.parse('./test.html', etree.HTMLParser())
result = etree.tostring(html)
print('\n 读取文本解析')
print(result.decode('utf-8'))

# 5. 所有节点
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')  # 用//开头的规则来取得所有节点
print('\n 所有节点')
print(result)  # 返回值为列表,每个元素为Element类型,后面跟着节点名称

# 6.子节点
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a')
# result=html.xpath('//ul//a')   #等价效果,选取ul的孙子节点a
print('\n li下的直接子节点a')
print(result)

# 7.父节点
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/../@class')
# result = html.xpath('//a[@href="link4.html"]/parent::*/@class')  #parent::获取父节点
print('获得父节点')
print(result)

# 8.属性匹配
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]')
# result=html.xpath('//a[@href="link1.html"]/text()') #diy练习
print('属相匹配')
print(result)

# 9.文本获取
# result = html.xpath('//li[@class="item-0"]/text()')
# result = html.xpath('//li[@class="item-0"]//text()') #直接从孙子节点获取,会带有其他符号
result = html.xpath('//li[@class="item-0"]/a/text()')  # 从子节点获取文本更准确
print('文本获取')
print(result)

# 10.获取属性的值
# result = html.xpath('//li/@class')
result = html.xpath('//li/a/@href')
print('获取属性的值')
print(result)

# 11.属性多值匹配
text11 = '''<li class="li dk li-first"><a href="link1.html">first 1 item</a></li>'''
html = etree.HTML(text11)
'''
# contains(属性名称,属性值)方法,匹配含有多个属性的节点,属性值可以是其中任意一个
'''
result = html.xpath('//li[contains(@class,"dk")]/a/text()')
print('属性多值匹配')
print(result)

# 12. 多属性匹配
'''
多个属性确定一个节点,需要同时匹配多个属性,用and运算符连接
'''
text12 = '''<li gk='xa' class="li dk li-first" name="item">
<a href="link12.html">first 12 item</a></li>'''
html = etree.HTML(text12)
result = html.xpath('//li[contains(@class,"dk") and @name="item"]/a/text()')
print('多属性匹配')
print(result)

# 13.按序选择
print('按序选择')
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[1]/a/text()')
print('获取第一个节点')
print(result)
result = html.xpath('//li[last()]/a/text()')
print('获取最后一个节点')
print(result)
result = html.xpath('//li[position()<3]/a/text()')
print('获取位置小于3的节点')
print(result)
result = html.xpath('//li[last()-2]/a/text()')
print('获取倒数第三个节点,last()-2,倒退2个即为倒数第三')
print(result)

# 14. 节点轴选择
text14 = '''
<div>
    <ul>
        <li class="item-0"><a href="link1.html"><span>first item</span></a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
        <li class="item-inactive"><a href="link3.htm">third item</a></li>
        <li class="item-1"><a href="link4.html">fourth item</a></li>
        <li class="item-0"><a href="link5.html">fifth item</a>
        </li>
    </ul>
</div>
'''
print('\n')
print('节点轴选择')
html = etree.parse('./test14.html', etree.HTMLParser())
result = html.xpath('//li[1]/ancestor::*')
print('1.获取所有祖先节点')
print(result)
result = html.xpath('//li[1]/ancestor::div')
print('2.获取祖先节点中的div节点')
print(result)
result = html.xpath('//li[1]/attribute::*')
print('3.获取指定节点的所有属性值')
print(result)
result = html.xpath('//li[1]/child::a[@href="link1.html"]')
print('4.获取指定子节点的属性值,当前限定为href属性为link.html的a节点')
print(result)
result = html.xpath('//li[1]/descendant::span')
print('5.获取所有子孙节点,结果有a和span节点,当前限定获得span节点')
print(result)
result = html.xpath('//li[1]/following::*[2]')
print('6.获取当前节点的后续节点,索引获取其中的第二个节点')
print(result)
result = html.xpath('//li[1]/following-sibling::*')
print('7.获得当前节点的所有同级节点')
print(result)
